using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace PS.WebParts.Rollup.Core
{
    class Join : SetOperation
    {
        public enum Type { Inner, Left, Right }
        public enum Op {Eq, Neq}
        public enum CorrelationType {None, Web}
        
        public  Join (string leftId)
        {
            this.baseId = leftId;
        }

        public Join(string leftId, string expr) : this (leftId)
        {
            Parse(expr);
        }

        //INNER JOIN ID2 ON ID1.1 = ID2.2
        public void Parse(string expr)
        {
            if (string.IsNullOrEmpty(expr))
                throw new ArgumentNullException("expr");

            string uExpr = expr.ToUpper();
            string[] j1 = uExpr.Split(new string[] {"JOIN"}, StringSplitOptions.RemoveEmptyEntries);

            if (j1.Length != 2)
                throw new FormatException("JOIN missing: " + expr);

            this.type = (Type)Enum.Parse(typeof (Type), j1[0], true);

            string right = j1[1].Trim();
            if (right.IndexOf("ON") <= 0)
                throw new FormatException("ON missing: " + right);

            string[] on1 = right.Split(new string[] {"ON"}, StringSplitOptions.RemoveEmptyEntries);

            this.joineeId = on1[0].Trim();

            string expression = on1[1].Trim();

            Regex regex = new Regex(@"([A-Z0-9]+)\.([A-Z0-9_]+)\s*(=|!=|<>)\s*([A-Z0-9]+)\.([A-Z0-9_]+)");
            Match match = regex.Match(expression);

            if (!match.Success && match.Groups.Count != 5)
                throw new FormatException("Expression unrecognized: " + expression);

            this.baseColumn = match.Groups[2].Value;
            this.joineeColumn = match.Groups[5].Value;

            string idLeft = match.Groups[1].Value;
            string idRight = match.Groups[4].Value;
            this.baseId = idLeft != this.baseId ? idRight : idLeft;

            string op1 = match.Groups[3].Value;
            switch(op1)
            {
                case "=":
                    this.operation = Op.Eq;
                    break;

                case "!=":
                case "<>":
                    this.operation = Op.Neq;
                    break;

            }
        }

        Op operation;
        Type type;
        CorrelationType correlationType;
        string joineeId;
        string baseColumn;
        string joineeColumn;
        private string correlatedQuery;

        public CorrelationType Correlate
        {
            get { return correlationType; }
            set { correlationType = value; }
        }

        public Type JoinType
        {
            get { return type; }
            set { type = value; }
        }

        public string JoineeId
        {
            get { return joineeId; }
            set { joineeId = value; }
        }

        public string BaseColumn
        {
            get { return baseColumn; }
            set { baseColumn = value; }
        }

        public string JoineeColumn
        {
            get { return joineeColumn; }
            set { joineeColumn = value; }
        }

        public Op Operation
        {
            get { return operation; }
            set { operation = value; }
        }

        public string CorrelatedQuery
        {
            get
            {
                return correlatedQuery;
            }
            set
            {
                correlatedQuery = value;
            }
        }

        private string excludeFields;

        public string ExcludeFields
        {
            get
            {
                return excludeFields;
            }
            set
            {
                excludeFields = value;
            }
        }


        private string includeFields;

        public string IncludeFields
        {
            get
            {
                return includeFields;
            }
            set
            {
                includeFields = value;
            }
        }

        public List<string> GetIncludedRightFields()
        {
            if (!string.IsNullOrEmpty(includeFields))
            {
                string[] arr = includeFields.Split(',');
                return new List<string>(arr);
            }
            else
                return new List<string>();
        }


        public List<string> GetExcludedRightFields()
        {
            if (!string.IsNullOrEmpty(excludeFields))
            {
                string[] arr = excludeFields.Split(',');
                return  new List<string>(arr);
            }
            else 
                return  new List<string>();
        }

        //INNER JOIN DSC5 ON DSC4.4 = DSC5.5
        public override string ToString()
        {
            string op=null;
            switch(operation)
            {
                case Op.Eq:
                    op = "=";
                    break;
                case Op.Neq:
                    op = "!=";
                    break;
            }
            
            return
                string.Format("{2} {0} JOIN {1} ON {2}.{3} {4} {5}.{6}", type.ToString().ToUpper(), joineeId, baseId, baseColumn, op,
                              joineeId, joineeColumn);
        }
    }
}
